﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlTypes;
using Noris.Schedule.Support;
using Noris.Schedule.Support.Services;
using Noris.Schedule.Support.Data;
using Noris.Schedule.Planning.DataFace;

namespace Noris.Schedule.Planning.ProcessData
{
    #region CLASS PlanningInteractiveArgs : Bázová třída pro vstupní a výstupní data interaktivních procesů
    /// <summary>
    /// PlanningInteractiveArgs : Bázová třída pro vstupní a výstupní data interaktivních procesů
    /// </summary>
    public class PlanningInteractiveArgs
    {
        #region Konstrukce, instanční proměnné
        /// <summary>
        /// Implicitní konstruktor
        /// </summary>
        public PlanningInteractiveArgs()
        {
            _SelectedElements = new List<DataPointerStr>();
            _NewRows = new Dictionary<GID, IDataRow>();
            _ChangedRows = new Dictionary<GID, object>();
            _DeletedRows = new Dictionary<GID, object>();
            _NewItems = new List<DataPointerStr>();
            _DeletedItems = new List<DataPointerStr>();
            _ChangedItems = new List<DataPointerStr>();
        }
        /// <summary>Pole vstupních elementů</summary>
        protected List<DataPointerStr> _SelectedElements;
        /// <summary>Dictionary GID řádků, které jsou metodou vytvořeny. Mohou / nemusí obsahovat data (Value). Klíč (GID) obsahovat musí.</summary>
        protected Dictionary<GID, IDataRow> _NewRows;
        /// <summary>Dictionary GID řádků, které jsou metodou změněny</summary>
        protected Dictionary<GID, object> _ChangedRows;
        /// <summary>Dictionary GID řádků, které jsou metodou smazány</summary>
        protected Dictionary<GID, object> _DeletedRows;
        /// <summary>Pole nových elementů</summary>
        protected List<DataPointerStr> _NewItems;
        /// <summary>Pole změněných elementů</summary>
        protected List<DataPointerStr> _ChangedItems;
        /// <summary>Pole odebraných elementů</summary>
        protected List<DataPointerStr> _DeletedItems;
        /// <summary>Příznak změny seznamu linkovaných elementů</summary>
        protected bool _ResultElementLinkListChanged;
        #endregion
        #region Public property
        /// <summary>
        /// Soupis pointerů na položky, které jsou vstupní. Plní se podle druhu funkcionality.
        /// </summary>
        public List<DataPointerStr> SelectedElements { get { return _SelectedElements; } }
        /// <summary>Dictionary GID řádků, které jsou metodou vytvořeny. Mohou / nemusí obsahovat data (Value). Klíč (GID) obsahovat musí. Tato property je přímá reference na interní Dictionary, lze do ní přidávat záznamy.</summary>
        public Dictionary<GID, IDataRow> NewRowsDict { get { return this._NewRows; } }
        /// <summary>
        /// Soupis GID řádků, které se editací vytvořily. Výstupní seznam.
        /// Tyto řádky je třeba explicitně donačíst z datového zdroje a zatřídit do grafů.
        /// Toto donačtení si provede každý graf sám pro sebe přes svůj datový zdroj, provede to okamžitě takže výsledky budou v grafu okamžitě vidět.
        /// </summary>
        public List<GID> NewRows { get { return new List<GID>(_NewRows.Keys); } }
        /// <summary>
        /// Soupis připravených dat řádků, které se editací vytvořily. Výstupní seznam.
        /// Tyto řádky si grafy převezmou a zatřídí do sebe.
        /// Které grafy to budou:
        /// 1) vždy grafy, jejichž RowGraphMode je shodný s režimem uvedeným v řádku v property RowGraph, a přitom:
        /// a) pro řádky, které jako ParentGId uvádí třídu bez záznamu to budou grafy, které mají shodnou třídu pro svá data 
        /// b) pro řádky, které jako ParentGId uvádí i konkrétní záznam (ParentGId.RecordNumber není nula) to budou grafy, které v sobě mají řádek uvedený jako Parent.
        /// Toto doplnění se provede okamžitě takže výsledky budou v grafu okamžitě vidět.
        /// </summary>
        public List<IDataRow> NewRowsData { get { return new List<IDataRow>(_NewRows.Values.Where(row => (row != null))); } }
        /// <summary>
        /// Soupis GID řádků, jejichž data se změnila. Výstupní seznam.
        /// Má dojít k invalidaci obsahu řádků (elementy), ale nikoli ke změně řádku nebo jeho podřízených řádků.
        /// </summary>
        public List<GID> ChangedRows { get { return new List<GID>(_ChangedRows.Keys); } }
        /// <summary>
        /// Soupis GID řádků, které se editací odstranily. Výstupní seznam.
        /// Tyto řádky je třeba odstranit z grafů, včetně sítě jejich podřízených nodů.
        /// Řádky, představující podřízené nody ke zde uvedeným řádkům, se z grafů neodebírají (mohou být podřízené některému jinému nodu).
        /// </summary>
        public List<GID> DeletedRows { get { return new List<GID>(_DeletedRows.Keys); } }
        /// <summary>
        /// Soupis pointerů na položky, které se přidaly. Výstupní seznam. Tyto položky je třeba přidat do vizuální vrstvy.
        /// </summary>
        public List<DataPointerStr> NewItems { get { return _NewItems; } }
        /// <summary>
        /// Soupis pointerů na položky, které se smazaly. Výstupní seznam. Tyto položky je třeba odebrat z vizuální vrstvy.
        /// </summary>
        public List<DataPointerStr> DeletedItems { get { return _DeletedItems; } }
        /// <summary>
        /// Soupis pointerů na položky, které se změnily. Výstupní seznam. Tyto položky je třeba přenačíst do vizuální vrstvy.
        /// </summary>
        public List<DataPointerStr> ChangedItems { get { return _ChangedItems; } }
        /// <summary>
        /// Příznak, že vlivem procesu došlo ke změnám v seznamu linkovaných elementů.
        /// Pokud je při skončení procesu nastaveno na true, 
        /// pak si vizuální vrstva vyžádá seznam linků z datového zdroje (request typu DataSourceRequestType.CreateDataLinkNet).
        /// </summary>
        public bool ResultElementLinkListChanged { get { return _ResultElementLinkListChanged; } set { _ResultElementLinkListChanged = value; } }
        #endregion
        #region Public metody. Služby pro Plánovací proces.
        /// <summary>
        /// Do interního seznamu NewRows přidá další položku, která byla vytvořena.
        /// </summary>
        /// <param name="rowGIdList"></param>
        public void AddNewRow(GID rowGId)
        {
            this.AddNewRow(rowGId, null);
        }
        /// <summary>
        /// Do interního seznamu NewRows přidá další řádek, který byl vytvořen.
        /// </summary>
        /// <param name="rowGIdList"></param>
        public void AddNewRow(IDataRow row)
        {
            this.AddNewRow(row.GId, row);
        }
        /// <summary>
        /// Do interního seznamu NewRows přidá další položky, které byly vytvořeny.
        /// </summary>
        /// <param name="rowGIdList"></param>
        public void AddNewRows(IEnumerable<GID> rowGIdList)
        {
            if (rowGIdList == null) return;
            foreach (GID rowGId in rowGIdList)
                this.AddNewRow(rowGId, null);
        }
        /// <summary>
        /// Do interního seznamu NewRows přidá další řádky, které byly vytvořeny.
        /// </summary>
        /// <param name="rowGIdList"></param>
        public void AddNewRows(IEnumerable<IDataRow> rowList)
        {
            if (rowList == null) return;
            foreach (IDataRow row in rowList)
                this.AddNewRow(row.GId, row);
        }
        /// <summary>
        /// Přidá info o nově vytvořeném řádku
        /// </summary>
        /// <param name="rowGId"></param>
        /// <param name="row"></param>
        protected void AddNewRow(GID rowGId, IDataRow row)
        {
            if (this._NewRows.ContainsKey(rowGId))
                this._NewRows[rowGId] = row;
            else
                this._NewRows.Add(rowGId, row);
        }
        /// <summary>
        /// Do interního seznamu ChangedRows přidá další řádky, které byly změněny.
        /// </summary>
        public void AddChangedRows(IEnumerable<GID> rowGIdList)
        {
            if (rowGIdList == null) return;
            foreach (GID rowGId in rowGIdList)
                this.AddChangedRow(rowGId);
        }
        /// <summary>
        /// Do interního seznamu ChangedRows přidá další řádek, která byla změněna.
        /// Položka je zadána jako WorkUnitCls, převezme se jeho workUnit.DataPointer.Row.
        /// </summary>
        public void AddChangedRow(WorkUnitCls workUnit)
        {
            AddChangedRow(workUnit.DataPointer.Row);
        }
        /// <summary>
        /// Do interního seznamu ChangedRows přidá další řádek, která byla změněna.
        /// Položka je zadána jako GID.
        /// </summary>
        public void AddChangedRow(GID rowGId)
        {
            if (rowGId.NotEmpty && !_ChangedRows.ContainsKey(rowGId))
                _ChangedRows.Add(rowGId, null);
        }
        /// <summary>
        /// Do interního seznamu DeletedRows přidá další řádky, které byly smazány.
        /// </summary>
        public void AddDeletedRows(IEnumerable<GID> rowGIdList)
        {
            if (rowGIdList == null) return;
            foreach (GID rowGId in rowGIdList)
                this.AddDeletedRow(rowGId);
        }
        /// <summary>
        /// Do interního seznamu DeletedRows přidá další řádek, který byly smazán.
        /// </summary>
        public void AddDeletedRow(GID rowGId)
        {
            if (rowGId.NotEmpty && !_DeletedRows.ContainsKey(rowGId))
                _DeletedRows.Add(rowGId, null);
        }
        /// <summary>
        /// Do interního seznamu NewItems přidá další položku, která byla přidaná.
        /// Položka je na vstupu ve formě WorkUnitCls, z ní se odvodí DataPointerStr.
        /// </summary>
        public void AddNewItem(WorkUnitCls workUnit)
        {
            this.AddItemTo(workUnit.DataPointer, this._NewItems);
        }
        /// <summary>
        /// Do interního seznamu DeletedItems přidá další položku, která byla smazaná.
        /// Položka je na vstupu ve formě WorkUnitCls, z ní se odvodí DataPointerStr.
        /// </summary>
        public void AddDeletedItem(WorkUnitCls workUnit)
        {
            this.AddItemTo(workUnit.DataPointer, this._DeletedItems);
        }
        /// <summary>
        /// Do interního seznamu DeletedItems přidá další položku, která byla smazaná.
        /// Položka je na vstupu ve formě DataPointerStr, což je pointer na element (řádek, element).
        /// </summary>
        public void AddDeletedItem(DataPointerStr dataPointer)
        {
            this.AddItemTo(dataPointer, this._DeletedItems);
        }
        /// <summary>
        /// Do interního seznamu ChangedItems přidá další položku, která byla změněna.
        /// Položka je na vstupu ve formě WorkUnitCls, z ní se odvodí DataPointerStr.
        /// </summary>
        public void AddChangedItem(WorkUnitCls workUnit)
        {
            this.AddItemTo(workUnit.DataPointer, this._ChangedItems);
        }
        /// <summary>
        /// Přidá pointer do daného pole, případně přidá řádek do seznamu _ChangedRows (pokud tam neexistuje).
        /// </summary>
        /// <param name="list"></param>
        /// <param name="dataPointer"></param>
        protected void AddItemTo(DataPointerStr dataPointer, List<DataPointerStr> list)
        {
            list.Add(dataPointer);
            AddChangedRow(dataPointer.Row);
        }
        #endregion
        #region Public metody. Služby pro Volající stranu (funkce, plánovací tabule).
        /// <summary>
        /// Naplní do this.SelectedElements (parametry do plánovacího procesu) seznam elementů vybraných v plánovací tabuli 
        /// ze seznamu funcArgs.SelectedElements
        /// </summary>
        /// <param name="funcArgs">Data, která předává grafická vrstva do výkonné metody funkcí</param>
        public void InputItemsFillFrom(FunctionMenuItemRunArgs funcArgs, bool addClickedItem, bool addSelectedItem)
        {
            this._SelectedElements = new List<DataPointerStr>();
            if (addClickedItem)
                this._SelectedElements.Add(funcArgs.ClickedItem);
            if (addSelectedItem)
                this._SelectedElements.AddRange(funcArgs.SelectedElements);
        }
        /// <summary>
        /// Překopíruje výsledky z this do požadavku typu DataSourceRequestEventAfterEdit.
        /// Plní property result.ResultEditChangedRows, ResultEditNewElements, ResultEditChangedElements, ResultEditDeletedElements, ResultElementLinkListChanged.
        /// </summary>
        /// <param name="request"></param>
        public virtual void ResultCopyTo(DataSourceRequestEventAfterEdit request)
        {
            request.ResultEditChangedRows = new List<GID>(this.ChangedRows);
            request.ResultEditNewElements = new List<DataPointerStr>(this.NewItems);
            request.ResultEditChangedElements = new List<DataPointerStr>(this.ChangedItems);
            request.ResultEditDeletedElements = new List<DataPointerStr>(this.DeletedItems);
            request.ResultElementLinkListChanged |= this.ResultElementLinkListChanged;
        }
        /// <summary>
        /// Uloží změny dat zachycené v this (kam je vepisuje plánovací proces ve svých interaktivních metodách) do argumentu funkce (funcArgs).
        /// Tak se dostanou do vizuální vrstvy, kde na ně reagují grafy.
        /// </summary>
        /// <param name="funcArgs">Data, která předává grafická vrstva do výkonné metody funkcí, a kde očekává výsledky</param>
        public virtual void ResultCopyTo(FunctionMenuItemRunArgs funcArgs)
        {
            funcArgs.ResultEditNewRows.AddRange(this._NewRows.Keys);
            funcArgs.ResultEditNewDataRows.AddRange(this._NewRows.Values.Where(row => (row != null)));
            funcArgs.ResultEditChangedRows.AddRange(this._ChangedRows.Keys);
            funcArgs.ResultEditDeletedRows.AddRange(this._DeletedRows.Keys);
            funcArgs.ResultElementLinkListChanged |= this.ResultElementLinkListChanged;
        }
        /// <summary>
        /// Uloží změny dat zachycené v this (kam je vepisuje plánovací proces ve svých interaktivních metodách) do argumentu funkce (funcArgs).
        /// Tak se dostanou do vizuální vrstvy, kde na ně reagují grafy.
        /// </summary>
        /// <param name="funcArgs">Data, která předává grafická vrstva do výkonné metody funkcí, a kde očekává výsledky</param>
        public virtual void ChangedRowsCopyTo(FunctionMenuItemRunArgs funcArgs)
        {
            this.ResultCopyTo(funcArgs);
        }
        #endregion
    }
    #endregion
    #region CLASS PlanningInteractiveRegisterArgs : Třída s property pro podporu interaktivní přeregistrace kapacit
    /// <summary>
    /// PlanningInteractiveRegisterArgs : Bázová třída pro vstupní a výstupní data interaktivních procesů
    /// </summary>
    public class PlanningInteractiveRegisterArgs : PlanningInteractiveArgs
    {
        #region KONSTRUKCE, PROMĚNNÉ
        /// <summary>
        /// Implicitní konstruktor
        /// </summary>
        public PlanningInteractiveRegisterArgs()
        {
            CapacityLimitForActiveTask = LimitedCType.ByPUCsetting;
            CapacityLimitForActiveTree = LimitedCType.ByPUCsetting;
            PullAdjacentForActiveTask = false;
            PullAdjacentForActiveTree = false;
            AutoMoveLinkedTask = AutoMoveLinkedTaskMode.NoMove;
        }
        /// <summary> { get; set; }
        /// Volba omezení kapacit při přesunu všech položek jednoho tasku (tj. jedna celá operace, může mít více pracovních úseků), která souvisí s aktivní položkou.
        /// Zadáním hodnoty do této property lze zajistit např. zaplánování do neomezených kapacit = pak se plánuje jako by v pracovním čase nebyla žádná jiná práce.
        /// <para>Default je LimitedCType.ByPUCsetting = podle kapacitní jednotky (ta na sobě má svůj příznak omezené / neomezené kapacity).</para>
        /// </summary>
        public LimitedCType CapacityLimitForActiveTask { get; set; }
        /// <summary> { get; set; }
        /// Volba omezení kapacit při přesunu všech návazných operací (tasků) okolo přesouvané operace.
        /// Zadáním hodnoty do této property lze zajistit např. zaplánování do neomezených kapacit = pak se plánuje jako by v pracovním čase nebyla žádná jiná práce.
        /// <para>Default je LimitedCType.ByPUCsetting = podle kapacitní jednotky (ta na sobě má svůj příznak omezené / neomezené kapacity).</para>
        /// </summary>
        public LimitedCType CapacityLimitForActiveTree { get; set; }
        /// <summary>
        /// Režim přesouvání záznamů v AKTUÁLNÍM TASKU: pokud přesunutím vznikne mezera, zkusit jí využít
        /// (tzv. přitáhnout sousední pracovní čas, když se od ní odsunu)
        /// </summary>
        public bool PullAdjacentForActiveTask { get; set; }
        /// <summary>
        /// Režim přesouvání záznamů pro SOUSEDNÍ ZÁZNAMY (tzn. i osu S): pokud přesunutím vznikne mezera, zkusit jí využít
        /// (tzv. přitáhnout sousední operaci / záznam osy S, když se od ní odsunu)
        /// </summary>
        public bool PullAdjacentForActiveTree { get; set; }
        /// <summary>
        /// <para>
        /// Režim automatického posouvání linkovaných tasků, pokud bude posouván jeden task ze skupiny.
        /// Určuje, zda se budou posouvat i linkované tasky, když nejsou explicitně vybrané (vždy / jen když jsou již na začátku časově synchronní).
        /// </para>
        /// <para>
        /// Defaultní hodnota = NoMove.
        /// </para>
        /// <para>
        /// Pokud jsou v linkované skupině tři operace (A, B, C), a uživatel pohybuje elementem operace A, pak zde nastavujeme zda se mají pohnout i operace B a C.
        /// Volba NoMove = operace se nepohnou.
        /// Volba MoveWhenSynchronized = operace B a C se pohnou tehdy, když mají společný začátek / konec, pohnou se tak, aby i po pohybu operace A měly společný začátek / konec.
        /// Volba MoveAlways = operace B a C se pohnou vždy, a to tak, aby po pohybu operace A měly od počátku / konce operace A stejný odstup, jaký měly před provedením pohybu.
        /// </para>
        /// </summary>
        public AutoMoveLinkedTaskMode AutoMoveLinkedTask { get; set; }
        #endregion
    }
    /// <summary>
    ///  Režim automatického posouvání linkovaných tasků, pokud bude posouván jeden task ze skupiny.
    /// </summary>
    public enum AutoMoveLinkedTaskMode
    {
        /// <summary>
        /// NoMove = operace se nepohnou. Defaultní hodnota.
        /// </summary>
        NoMove,
        /// <summary>
        /// Linkované operace (B a C) se pohnou tehdy, když mají společný začátek / konec s aktivní operací (A), pohnou se tak, aby i po pohybu operace A měly společný začátek / konec.
        /// </summary>
        MoveWhenSynchronized,
        /// <summary>
        /// Linkované operace (B a C) se pohnou vždy, a to tak, aby po pohybu aktivní operace A měly od počátku / konce operace A stejný odstup, jaký měly před provedením pohybu.
        /// </summary>
        MoveAlways
    }
    #endregion
    #region CLASS PlanningInteractiveMoveArgs : Data pro řízení interaktivního přeplánování
    /// <summary>
    /// Data pro řízení interaktivního přeplánování
    /// </summary>
    public class PlanningInteractiveMoveArgs : PlanningInteractiveRegisterArgs
    {
        /// <summary>
        /// Vytvoří nový argument PlanningInteractiveMoveArgs.
        /// Po jeho vytvoření je možno do něj přidat položky, které je požadováno posunout.
        /// Po doběhnutí metody pro posunutí dat (PlanningDataCls.InteractiveMove()) jsou v argumentu naplněny informace 
        /// o položkách a řádcích, kde došlo ke změně (tyto řádky je třeba překreslit v grafu).
        /// </summary>
        public PlanningInteractiveMoveArgs()
        {
            _ActiveItemList = new List<PlanningInteractiveMoveActiveItem>();
            _SetFixedTask = false;
            _EditActiveItemDict = new Dictionary<DataPointerStr, object>();
            _MoveTaskVectorDict = new Dictionary<GID, TimeVector>();
        }
        private List<PlanningInteractiveMoveActiveItem> _ActiveItemList;
        private Dictionary<GID, TimeVector> _MoveTaskVectorDict;
        private bool _SetFixedTask;
        private Dictionary<DataPointerStr, object> _EditActiveItemDict;
        /// <summary>
        /// Soupis položek, které se mají přesunout. Vstupní seznam elementů, které obsahují změnu.
        /// </summary>
        public List<PlanningInteractiveMoveActiveItem> ActiveItemList { get { return _ActiveItemList; } }
        /// <summary>
        /// Soupis klíčů tasků (GID tasku), které se mají přeregistrovat a jejich cílových časů (TimeVector).
        /// Jde o alternatvní zadání přesunu, kdy nepotřebujeme deklarovat konkrétní element (WorkUnit), ale potřebujeme přesunout celý task tak, aby začínal / končil v daný čas.
        /// Touto cestou (zatím) nelze přeplánovat na jinou kapacitní jednotku.
        /// </summary>
        public Dictionary<GID, TimeVector> MoveTaskVectorDict { get { return _MoveTaskVectorDict; } }
        /// <summary> { get; set; }
        /// Požadavek na zafixování operace (tasku), do které náleží aktivní položka.
        /// true = po přesunutí se provede její zafixování (pokud dosud není).
        /// false = fixování se neprovede.
        /// Pokud operace již je fixovaná, zůstane tak i poté (požadavek = false nezpůsobí zrušení fixace).
        /// </summary>
        public bool SetFixedTask { get { return this._SetFixedTask; } set { this._SetFixedTask = value; } }
        /// <summary>
        /// Soupis pointerů na položky, které mají být aktivní po dokončení editace.
        /// Jsou to nové položky, odpovídající počtem a umístěním položkám vstupním (ActiveItemList).
        /// </summary>
        public List<DataPointerStr> EditActiveItems { get { return new List<DataPointerStr>(_EditActiveItemDict.Keys); } }
        /// <summary>
        /// Do interního seznamu ActiveItemList přidá další položku, pokud tam položka se shodným WorkID dosud není.
        /// </summary>
        /// <param name="activeItem"></param>
        public void AddActiveItem(PlanningInteractiveMoveActiveItem activeItem)
        {
            if (!this._ActiveItemList.Exists(delegate(PlanningInteractiveMoveActiveItem i) { return (i.WorkID == activeItem.WorkID); }))
                this._ActiveItemList.Add(activeItem);
        }
        /// <summary>
        /// Do interního seznamu EditActiveItems přidá další položku (pokud tam dosud není).
        /// </summary>
        /// <param name="dataPointer"></param>
        public void AddEditActiveItem(DataPointerStr dataPointer)
        {
            if (!this._EditActiveItemDict.ContainsKey(dataPointer))
                this._EditActiveItemDict.Add(dataPointer, null);
        }
        /// <summary>
        /// Překopíruje výsledky z this do požadavku typu DataSourceRequestEventAfterEdit.
        /// Plní property result.ResultEditChangedRows, ResultEditNewElements, ResultEditChangedElements, ResultEditDeletedElements, ResultEditActiveElementPointers, ResultElementLinkListChanged.
        /// </summary>
        /// <param name="request"></param>
        public override void ResultCopyTo(DataSourceRequestEventAfterEdit request)
        {
            base.ResultCopyTo(request);
            request.ResultEditActiveElementPointers = new List<DataPointerStr>(this.EditActiveItems);
        }
        #region Diagnostika
        /// <summary>
        /// Metoda zapíše do Logu obsah argumentu = požadavky na přesun, do Steward.Diagnostic.
        /// </summary>
        /// <param name="planningDataCls"></param>
        internal void AddToDiagnostic(PlanningDataCls planningDataCls, string title, string rowPrefix)
        {
            if (!String.IsNullOrEmpty(title))
                Steward.Diagnostic.TitleAdd(title);
            string pref = (rowPrefix == null ? "" : rowPrefix);
            for (int i = 0; i < this.ActiveItemList.Count; i++)
            {
                PlanningInteractiveMoveActiveItem activeItem = this.ActiveItemList[i];
                Steward.Diagnostic.InfoAddLine(pref + "ActiveItem[" + i.ToString() + "]");
                activeItem.AddToDiagnostic(planningDataCls, null, "        ");
            }
        }
        /// <summary>
        /// Vrátí seznam tasků, kterých se týkají změny.
        /// </summary>
        /// <param name="planningDataCls"></param>
        /// <returns></returns>
        internal List<CapacityPlanWorkItemCls> GetTaskList(PlanningDataCls planningDataCls)
        {
            List<CapacityPlanWorkItemCls> result = new List<CapacityPlanWorkItemCls>();
            foreach (PlanningInteractiveMoveActiveItem activeItem in this.ActiveItemList)
            {
                WorkUnitCls workUnit = planningDataCls.FindWorkUnit(activeItem.WorkID);
                if (workUnit != null && !result.Exists(t => t.TaskID == workUnit.TaskID))
                    result.Add(workUnit.TaskData);
            }
            foreach (KeyValuePair<GID, TimeVector> taskVector in this.MoveTaskVectorDict)
            {
                CapacityPlanWorkItemCls task = planningDataCls.FindTaskC(taskVector.Key);
                if (task != null && !result.Exists(t => t.TaskID == task.TaskID))
                    result.Add(task);
            }
            return result;
        }
        #endregion
    }
    #region CLASS PlanningInteractiveMoveActiveItem : Jedna položka interaktivního přeplánování kapacit
    /// <summary>
    /// Jedna položka interaktivního přeplánování kapacit
    /// </summary>
    public class PlanningInteractiveMoveActiveItem
    {
        /// <summary>
        /// Vytvoří položku na základě dat v elementu.
        /// Element musí být třídy (Constants.ClassNumberWork), a řádek musí být třídy (PlanUnitCCls.ClassNr).
        /// Jinak je vyhozena chyba.
        /// </summary>
        /// <param name="element"></param>
        public PlanningInteractiveMoveActiveItem(IDataElement element)
        {
            if (element.GId.ClassNumber != Constants.ClassNumberWork)
                Throw.SysError(MessageInfo.Get("Plánovací proces nepodporuje editaci jiných elementů, než třídy %0 (WorkUnitCls). Je požadována editace třídy %1.", Constants.ClassNumberWork, element.GId.ClassNumber));

            if (element.OriginalRowGId.ClassNumber != PlanUnitCCls.ClassNr)
                Throw.SysError(MessageInfo.Get("Plánovací proces nepodporuje editaci elementů pro jiné řádky, než třídy %0 (PlanUnitC). Je požadována editace třídy %1.", PlanUnitCCls.ClassNr, element.OriginalRowGId.ClassNumber));

            if (element.RowGId.ClassNumber != PlanUnitCCls.ClassNr)
                Throw.SysError(MessageInfo.Get("Plánovací proces nepodporuje editaci elementů pro jiné cílové řádky, než třídy %0 (PlanUnitC). Je požadována editace třídy %1.", PlanUnitCCls.ClassNr, element.RowGId.ClassNumber));

            _WorkID = element.GId.RecordNumber;
            _TimeRangeOrigin = element.OriginalTimeRange;
            _TimeRangeCurrent = element.TimeRange;
            _CapacityUnitOrigin = element.OriginalRowGId.RecordNumber;
            _CapacityUnitCurrent = element.RowGId.RecordNumber;
        }
        /// <summary>
        /// Vytvoří položku na základě výchozí jednotky WorkUnit a jednotlivých cílových dat.
        /// </summary>
        public PlanningInteractiveMoveActiveItem(WorkUnitCls workUnit, TimeRange timeRangeCurrent, int capacityUnitCurrent, int capacitySourceCurrent)
        {
            // Výchozí stav:
            _WorkID = workUnit.WorkID;
            _TimeRangeOrigin = workUnit.WorkTime;
            _CapacityUnitOrigin = workUnit.CapacityUnit;
            _CapacitySourceOrigin = workUnit.CapacitySource;

            // Cílový stav:
            _TimeRangeCurrent = timeRangeCurrent;
            _CapacityUnitCurrent = capacityUnitCurrent;
            _CapacitySourceCurrent = capacitySourceCurrent;
        }
        /// <summary>
        /// Vizualizace
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string text = "WorkID=" + this.WorkID.ToString();
            text += "; Time " + this.TimeRangeOrigin.ToString();
            if (this.IsChangedTime)
                text += " ChangeTo " + this.TimeRangeCurrent.ToString();
            text += "; CUnit " + this.CapacityUnitOrigin.ToString();
            if (this.IsChangedUnit)
                text += " ChangeTo " + this.CapacityUnitCurrent.ToString();

            return text;
        }
        private int _WorkID;
        private TimeRange _TimeRangeOrigin;
        private TimeRange _TimeRangeCurrent;
        private int _CapacityUnitOrigin;
        private int _CapacityUnitCurrent;
        private int _CapacitySourceOrigin;
        private int _CapacitySourceCurrent;
        /// <summary>
        /// Klíč WorkID = klíč jednotky práce = číslo záznamu elementu v grafech
        /// </summary>
        public int WorkID { get { return this._WorkID; } }
        /// <summary>
        /// Časový interval původní, měl by odpovídat časovému intervalu v záznamu WorkUnitCls.
        /// Zdejší údaj (TimeRangeOrigin) pochází z vizuální vrtsvy, která jej načetla z IDataElement.OriginalTimeRange,
        /// kam jej vložil konstruktor, typicky ve třídě PlanningVisualDataElementCls.
        /// </summary>
        public TimeRange TimeRangeOrigin { get { return this._TimeRangeOrigin; } }
        /// <summary>
        /// Časový interval jednotky práce po editaci. Tam by chtěl uživatel přesunout práci.
        /// Na vstupu není nijak zaručeno, že se podaří umístit práci přesně do tohoto času (nemusí tam být stav kapacit).
        /// </summary>
        public TimeRange TimeRangeCurrent { get { return this._TimeRangeCurrent; } }
        /// <summary>
        /// Kapacitní jednotka původní, měla by odpovídat hodnotě WorkUnitCls.UnitID.
        /// </summary>
        public int CapacityUnitOrigin { get { return this._CapacityUnitOrigin; } }
        /// <summary>
        /// Kapacitní jednotka po editaci. Tam by chtěl uživatel přesunout práci.
        /// </summary>
        public int CapacityUnitCurrent { get { return this._CapacityUnitCurrent; } }
        /// <summary>
        /// Kapacitní zdroj (obecný, například pracoviště, profese) původní. Default je nula.
        /// Pokud nebude uvedeno, systém si najde zdroj podle interních dat.
        /// Nejjednodušší je nechat hodnotu 0.
        /// </summary>
        public int CapacitySourceOrigin { get { return this._CapacitySourceOrigin; } set { this._CapacitySourceOrigin = value; } }
        /// <summary>
        /// Kapacitní zdroj (obecný, například pracoviště, profese) po editaci. Tam by chtěl uživatel přesunout práci.
        /// Default je nula.
        /// Nula značí, že ačkoliv se přesouvá část výroby na jiné místo (KPJ), bude se výroba tvářit, že jde o původní pracoviště (atd).
        /// Zadaná hodnota (nenulová) = výroba se přesune na jiné pracoviště / profesi.
        /// Pokud zadaná hodnota nebude odpovídat žádnému známému pracovišti / profesi / zdroji, bude vyvolána chyba.
        /// </summary>
        public int CapacitySourceCurrent { get { return this._CapacitySourceCurrent; } set { this._CapacitySourceCurrent = value; } }
        /// <summary>
        /// Obsahuje true, pokud zde existuje změna zdroje kapacit (Source)
        /// </summary>
        public bool IsChangedSource { get { return (this.CapacitySourceCurrent != 0 && this.CapacitySourceOrigin != this.CapacitySourceCurrent); } }
        /// <summary>
        /// Obsahuje true, pokud zde existuje změna kapacitní jednotky (Unit)
        /// </summary>
        public bool IsChangedUnit { get { return (this.CapacityUnitCurrent != 0 && this.CapacityUnitOrigin != this.CapacityUnitCurrent); } }
        /// <summary>
        /// Obsahuje true, pokud zde existuje změna časového intervalu
        /// </summary>
        public bool IsChangedTime { get { return (this._TimeRangeOrigin != this._TimeRangeCurrent); } }
        /// <summary>
        /// Obsahuje true, pokud zde existuje změna kapacitní jednotky anebo časového intervalu
        /// </summary>
        public bool IsChanged { get { return (IsChangedUnit || IsChangedTime); } }
        /// <summary>
        /// Obsahuje směr pohybu času = kam uživatel pohnul s časovým okamžikem
        /// </summary>
        public TimeRange.TimeDirection MoveDir { get { return _GetMoveDir(); } }
        /// <summary>
        /// Vrací směr pohybu času = kam uživatel pohnul s časovým okamžikem
        /// </summary>
        /// <returns></returns>
        private TimeRange.TimeDirection _GetMoveDir()
        {
            if (this.TimeRangeCurrent.Begin > this.TimeRangeOrigin.Begin)
                return TimeRange.TimeDirection.ToFuture;
            if (this.TimeRangeCurrent.Begin < this.TimeRangeOrigin.Begin)
                return TimeRange.TimeDirection.ToHistory;
            if (this.TimeRangeCurrent.End > this.TimeRangeOrigin.End)
                return TimeRange.TimeDirection.ToFuture;
            if (this.TimeRangeCurrent.End < this.TimeRangeOrigin.End)
                return TimeRange.TimeDirection.ToHistory;
            return TimeRange.TimeDirection.Stay;
        }
        /// <summary>
        /// Zajistí, že nebude generován požadavek na změnu času (TimeRangeCurrent == TimeRangeOrigin).
        /// </summary>
        internal void ResetTime()
        {
            this._TimeRangeCurrent = this.TimeRangeOrigin;
        }
        /// <summary>
        /// Zajistí, že nebude generován požadavek na změnu kapacitní jednotky (CapacityUnitCurrent == CapacityUnitOrigin).
        /// </summary>
        internal void ResetUnit()
        {
            this._CapacityUnitCurrent = this.CapacityUnitOrigin;
        }
        /// <summary>
        /// Tvorba diagnostiky
        /// </summary>
        /// <param name="planningDataCls"></param>
        /// <returns></returns>
        internal void AddToDiagnostic(PlanningDataCls planningDataCls, string title, string rowPrefix)
        {
            Steward.Diagnostic.SubTitleAdd(title);
            string pref = (rowPrefix == null ? "" : rowPrefix);
            WorkUnitCls workUnit = planningDataCls.FindWorkUnit(this.WorkID);
            if (workUnit == null)
            {
                Steward.Diagnostic.InfoAddLine(pref + "WorkID=" + this.WorkID.ToString() + "; NOT FOUND.");
            }
            else
            {
                string axisText = planningDataCls.GetReferNazev(workUnit.AxisData.AxisGID);
                string taskText = planningDataCls.GetReferNazev(workUnit.TaskData.TaskGID);
                Steward.Diagnostic.InfoAddLine(pref + "WorkID=" + this.WorkID.ToString() + "; Time Origin=" + this.TimeRangeOrigin.ToString() + "; Time Requested=" + this.TimeRangeCurrent.ToString());
                Steward.Diagnostic.InfoAddLine(pref + " Axis =" + axisText + ";     Task =" + taskText);
                if (this.IsChangedUnit || this.IsChangedSource)
                {
                    Steward.Diagnostic.InfoAddLine(pref + " Change from Source (" + this.CapacitySourceOrigin.ToString() + ")=" + planningDataCls.GetReferNazev(Constants.ClassNumberCapacitySource, this.CapacitySourceOrigin) +
                                                          ";   from Unit (" + this.CapacityUnitOrigin.ToString() + ")=" + planningDataCls.GetReferNazev(PlanUnitCCls.ClassNr, this.CapacityUnitOrigin));

                    Steward.Diagnostic.InfoAddLine(pref + "          to Source (" + this.CapacitySourceCurrent.ToString() + ")=" + planningDataCls.GetReferNazev(Constants.ClassNumberCapacitySource, this.CapacitySourceCurrent) +
                                                          ";     to Unit (" + this.CapacityUnitCurrent.ToString() + ")=" + planningDataCls.GetReferNazev(PlanUnitCCls.ClassNr, this.CapacityUnitCurrent));
                }
            }
        }
    }
    #endregion
    #endregion
    #region CLASS PlanningInteractiveFixArgs : Data pro řízení interaktivní fixace elementů
    /// <summary>
    /// PlanningInteractiveFixArgs : Data pro řízení interaktivní fixace elementů
    /// </summary>
    public class PlanningInteractiveFixArgs : PlanningInteractiveArgs
    {
        #region KONSTRUKCE A PROMĚNNÉ
        public PlanningInteractiveFixArgs()
        {
            this.FixSetting = InteractiveFixSetting.NoChange;
        }
        #endregion
        #region PROPERTY
        /// <summary>
        /// Režim fixace. Default = NoChange
        /// </summary>
        public InteractiveFixSetting FixSetting { get; set; }
        #endregion
    }
    #endregion
    #region CLASS PlanningInteractiveSplitAxisSArgs : Data pro řízení interaktivního rozdělení osy S
    /// <summary>
    /// PlanningInteractiveSplitAxisSArgs : Data pro řízení interaktivního rozdělení osy S
    /// </summary>
    public class PlanningInteractiveSplitAxisSArgs : PlanningInteractiveRegisterArgs
    {
        #region KONSTRUKCE A PROMĚNNÉ
        /// <summary>
        /// Konstruktor argumentu
        /// </summary>
        public PlanningInteractiveSplitAxisSArgs()
        {
            this.SplitItemList = new List<PlanningInteractiveSplitAxisSItemArgs>();
        }
        #endregion
        #region PUBLIC PROPERTY (dostupné pro uživatele služby)
        /// <summary>
        /// Položka, kterou je třeba rozdělit na více dílčích příjmů.
        /// Typicky by mělo jít o pointer na WorkUnit (element v grafu TaskLink), což je nejmenší jednotka práce.
        /// Alternativně je možno zadat pointer na celý task (element v grafu Gantt), tedy jde o operaci.
        /// Musí jít o operaci z NÁVRHU NA PŘÍJEM (kategorie Plán), nelze rozdělit VÝROBNÍ PŘÍKAZ (kategorie Realita)!
        /// </summary>
        public DataPointerStr SplitItemSource { get; set; }
        /// <summary>
        /// <para>
        /// Vstupní a výstupní pole, kde je zadáno požadované množství dílčích příjmů, 
        /// které mají vzniknout při rozdělení stávajícího množství (příjem na osu S) na jednotlivé dílčí příjmy.
        /// Jednotlivé položky v tomto poli na vstupu mají obsahovat: QtyRequired (množství) a RegisterTimeDir (směr registrace kapacit),
        /// volitelně může být naplněn Tag. 
        /// V průběhu přeregistrace výroby se do týchž položek doplní property: ResultAxisGId (klíč nové osy S)
        /// a ResultElementPointer (pointer na element WorkUnit, který nahrazuje původní element this.SplitItemSource).
        /// </para>
        /// <para>
        /// MNOŽSTVÍ: součet množství z jednotlivých položek SplitItemList[xx].QtyRequired by měl být shodný s původním množstvím na příjmu na osu S.
        /// Pokud se bude množství lišit: chybu to nezpůsobí, algoritmus se s tím vyrovná.
        /// Pokud bude součet požadovaného množství vyšší, než původní =» zaplánuje se požadované vyšší množství, a přebytek zůstane na skladě.
        /// Pokud bude součet požadovaného množství menší, než původní =» zaplánuje se požadované menší množství, zkontroluje se zajištění všech požadavků, 
        /// a v případě potřeby systém vygeneruje nový návrh na příjem v potřebném čase, a zaplánuje si jej.
        /// </para>
        /// </summary>
        public List<PlanningInteractiveSplitAxisSItemArgs> SplitItemList { get; set; }
        #endregion
        #region INTERNAL PROPERTY (potřebné pro interaktivní plánovací proces)
        /// <summary>
        /// Úložiště pro původní záznam aktuálního tasku, na který uživatel kliknul.
        /// V průběhu přeregistrace se tento task odebere z Axis i z kapacitního systému, jeho vnitřní struktura se rozloží a vynuluje.
        /// Tady zbyde jen skořápka = hlavička, a na konci funkce se vynuluje a uvolní i zbytek záznamu.
        /// </summary>
        internal CapacityPlanWorkItemCls CurrTaskData { get; set; }
        /// <summary>
        /// Úložiště pro původní záznam o elementu, na který uživatel kliknul.
        /// V průběhu přeregistrace se tento element odebere z Axis, z jeho tasku (při odregistraci kapacit) i z kapacitního systému.
        /// Tady zbyde jen sirotek objekt, na konci funkce se argument vynuluje a tím se uvolní i tento sirotek.
        /// </summary>
        internal WorkUnitCls CurrWorkUnit { get; set; }
        /// <summary>
        /// Relativní pozice elementu, který byl předán jako aktivní, v rámci jeho WorkPass
        /// </summary>
        internal WorkUnitLocationCls CurrElementLocation { get; set; }
        /// <summary>
        /// Úložiště pro původní záznam posledního tasku, který je finální operací před příjmem na osu, kterou budu dělit.
        /// V průběhu přeregistrace se tento task odebere z Axis i z kapacitního systému, jeho vnitřní struktura se rozloží a vynuluje.
        /// Tady zbyde jen skořápka = hlavička, a na konci funkce se vynuluje a uvolní i zbytek záznamu.
        /// </summary>
        internal CapacityPlanWorkItemCls LastTaskData { get; set; }
        /// <summary>
        /// Časový interval posledního tasku.
        /// Při požadavku na registraci ve směru ToFuture se bude vycházet při registraci poslední operace z tohoto času (Begin).
        /// Veškeré podřízené operace budou zaplánovány ToHistory od času Begin z vyšší operace.
        /// </summary>
        internal TimeRange LastTaskTime { get; set; }
        /// <summary>
        /// Úložiště pro původní záznam osy S, který odebíráme (z něj budu dělat dílčí příjmy).
        /// V průběhu přeregistrace se odebere z osy AxisHeap, odstraní se návazné pohyby na skladové kartě StockCard, 
        /// odeberou se a zahodí záznamy task, které se na tento záznam odkazují (ve své property Parent).
        /// Tady zbyde jen sirotek objekt, na konci funkce se argument vynuluje a tím se uvolní i tento sirotek.
        /// </summary>
        internal MaterialPlanAxisItemCls FinalAxisSData { get; set; }
        /// <summary>
        /// Úložiště pro skladovou kartu odpovídající záznamu osy S OriginalAxis, tam bude probíhat přeplánování cílového záznamu osy S.
        /// Tato skladová karta se v průběhu přeregistrace mění, ale nezahazuje se - stále je to karta, na které se plánuje.
        /// </summary>
        internal StockCardCls FinalStockCard { get; set; }
        /// <summary>
        /// Index záznamu o pohybu na skladové kartě, kde se nacházel původní záznam osy S (OriginalAxis), který se odebral,
        /// a kam budeme vkládat nově vystavené návrhy na příjem vzniklé rozdělením
        /// </summary>
        internal int FinalStockChangeIndex { get; set; }
        #endregion
    }
    #region CLASS PlanningInteractiveSplitAxisSItemArgs : Jedna položka při zadání požadavku na dělení výroby
    /// <summary>
    /// PlanningInteractiveSplitAxisSItemArgs : Jedna položka při zadání požadavku na dělení výroby
    /// </summary>
    public class PlanningInteractiveSplitAxisSItemArgs
    {
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby. Pozor: množství může být upraveno podle pravidel skladové karty, pokud nebude tato úprava zakázaná nastavením this.QtyDisableAdjustment = true</param>
        /// <param name="registerTimeDir">Směr alokace kapacit poslední operace.. Detaily viz property RegisterTimeDir, XML komentář (remarks).</param>
        public PlanningInteractiveSplitAxisSItemArgs(decimal qtyRequired, TimeRange.TimeDirection registerTimeDir)
        {
            this._Init(qtyRequired, registerTimeDir, SplitAxisSQtyAdjustmentMode.AdjustStandard, null);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby. Pozor: množství může být upraveno podle pravidel skladové karty, pokud nebude tato úprava zakázaná nastavením this.QtyDisableAdjustment = true</param>
        /// <param name="registerTimeDir">Směr alokace kapacit poslední operace.. Detaily viz property RegisterTimeDir, XML komentář (remarks).</param>
        /// <param name="tag">Libovolný objekt s daty, který je v této položce uložen pro identifikaci na straně volající aplikace.</param>
        public PlanningInteractiveSplitAxisSItemArgs(decimal qtyRequired, TimeRange.TimeDirection registerTimeDir, object tag)
        {
            this._Init(qtyRequired, registerTimeDir, SplitAxisSQtyAdjustmentMode.AdjustStandard, tag);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby. Pozor: množství může být upraveno podle pravidel skladové karty, pokud nebude tato úprava zakázaná nastavením this.QtyDisableAdjustment = true</param>
        /// <param name="registerTimeDir">Směr alokace kapacit poslední operace.. Detaily viz property RegisterTimeDir, XML komentář (remarks).</param>
        /// <param name="qtyDisableAdjustmentStockCard">Požadavek, aby množství uvedené v qtyRequired nebylo upravováno podle pravidel skladové karty</param>
        public PlanningInteractiveSplitAxisSItemArgs(decimal qtyRequired, TimeRange.TimeDirection registerTimeDir, bool qtyDisableAdjustmentStockCard)
        {
            this._Init(qtyRequired, registerTimeDir, (qtyDisableAdjustmentStockCard ? SplitAxisSQtyAdjustmentMode.AdjustByElementLoss : SplitAxisSQtyAdjustmentMode.AdjustStandard), null);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby. Pozor: množství může být upraveno podle pravidel skladové karty, pokud nebude tato úprava zakázaná nastavením this.QtyDisableAdjustment = true</param>
        /// <param name="registerTimeDir">Směr alokace kapacit poslední operace.. Detaily viz property RegisterTimeDir, XML komentář (remarks).</param>
        /// <param name="qtyDisableAdjustmentStockCard">Požadavek, aby množství uvedené v qtyRequired nebylo upravováno podle pravidel skladové karty</param>
        /// <param name="tag">Libovolný objekt s daty, který je v této položce uložen pro identifikaci na straně volající aplikace.</param>
        public PlanningInteractiveSplitAxisSItemArgs(decimal qtyRequired, TimeRange.TimeDirection registerTimeDir, bool qtyDisableAdjustmentStockCard, object tag)
        {
            this._Init(qtyRequired, registerTimeDir, (qtyDisableAdjustmentStockCard ? SplitAxisSQtyAdjustmentMode.AdjustByElementLoss : SplitAxisSQtyAdjustmentMode.AdjustStandard), tag);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby. Pozor: množství může být upraveno podle pravidel skladové karty, pokud nebude tato úprava zakázaná nastavením this.QtyDisableAdjustment = true</param>
        /// <param name="registerTimeDir">Směr alokace kapacit poslední operace.. Detaily viz property RegisterTimeDir, XML komentář (remarks).</param>
        /// <param name="qtyAdjustmentMode">Režim úpravy zadaného množství</param>
        public PlanningInteractiveSplitAxisSItemArgs(decimal qtyRequired, TimeRange.TimeDirection registerTimeDir, SplitAxisSQtyAdjustmentMode qtyAdjustmentMode)
        {
            this._Init(qtyRequired, registerTimeDir, qtyAdjustmentMode, null);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby. Pozor: množství může být upraveno podle pravidel skladové karty, pokud nebude tato úprava zakázaná nastavením this.QtyDisableAdjustment = true</param>
        /// <param name="registerTimeDir">Směr alokace kapacit poslední operace.. Detaily viz property RegisterTimeDir, XML komentář (remarks).</param>
        /// <param name="qtyAdjustmentMode">Režim úpravy zadaného množství</param>
        /// <param name="tag">Libovolný objekt s daty, který je v této položce uložen pro identifikaci na straně volající aplikace.</param>
        public PlanningInteractiveSplitAxisSItemArgs(decimal qtyRequired, TimeRange.TimeDirection registerTimeDir, SplitAxisSQtyAdjustmentMode qtyAdjustmentMode, object tag)
        {
            this._Init(qtyRequired, registerTimeDir, qtyAdjustmentMode, tag);
        }
        /// <summary>
        /// Inicializace hodnot
        /// </summary>
        /// <param name="qtyRequired"></param>
        /// <param name="registerTimeDir"></param>
        /// <param name="qtyAdjustmentMode"></param>
        /// <param name="tag"></param>
        private void _Init(decimal qtyRequired, TimeRange.TimeDirection registerTimeDir, SplitAxisSQtyAdjustmentMode qtyAdjustmentMode, object tag)
        {
            this.QtyRequired = qtyRequired;
            this.QtyAdjustmentMode = qtyAdjustmentMode;
            this.RegisterTimeDir = registerTimeDir;
            this.CurrentSupplier = GID.Empty;
            this.CurrentAOMod = 0;
            this.ResultQty = 0M;
            this.ResultAxisGIdList = new List<GID>();
            this.ResultElementPointerList = new List<DataPointerStr>();
            this.Tag = tag;
        }
        /// <summary>
        /// Množství požadované v tomto podílu rozdělené výroby.
        /// Pozor: množství může být upraveno podle pravidel skladové karty (maximální dávka, minimum od dodavatele, dělitel při nákupu), 
        /// pokud nebude tato úprava zakázaná nastavením this.QtyDisableAdjustment = true
        /// </summary>
        public decimal QtyRequired { get; protected set; }
        /// <summary>
        /// Režim úpravy množství
        /// </summary>
        public SplitAxisSQtyAdjustmentMode QtyAdjustmentMode { get; set; }
        /// <summary>
        /// Příznak, že množství uvedené v QtyRequired se má upravovat podle pravidel na skladové kartě (maximální dávka, minimum od dodavatele, dělitel při nákupu).
        /// true = množství neupravovat; false (default) = množství v QtyRequired bude upraveno podle pravidel skladové karty.
        /// </summary>
        public bool IsQtyAdjustByStockCard { get { return ((this.QtyAdjustmentMode & SplitAxisSQtyAdjustmentMode.AdjustByStockCard) != 0); } }
        /// <summary>
        /// Příznak, že množství uvedené v QtyRequired se má upravovat podle ztrát na dílci (podle K modifikace STPV: pevná ztráta, procento ztrát).
        /// true = množství neupravovat; false (default) = množství v QtyRequired bude upraveno hodnot K modifikace.
        /// </summary>
        public bool IsQtyAdjustByElementLoss { get { return ((this.QtyAdjustmentMode & SplitAxisSQtyAdjustmentMode.AdjustByElementLoss) != 0); } }
        /// <summary>
        /// Směr alokace kapacit poslední operace.
        /// Typicky se operace alokují od data požadovaného příjmu směrem do minulosti (ToHistory).
        /// Zde je umožněno, aby alokace poslední operace (pro tento podíl výroby) 
        /// proběhla od času okamžiku původního počátku poslední operace směrem do budoucnosti (ToFuture).
        /// Nižší operace budou vždy registrovány ToHistory od okamžiku reálného počátku poslední operace (tohoto podílu).
        /// </summary>
        /// <remarks>
        /// Pokud například máme operace 10 {čas od 2 do 8}, 20 { od 8 do 14}, 30 { od 14 do 20 }, a množství == 20,
        /// a pak zadáme rozdělení na množství (10, 8, 2), a všechny podíly ToFuture, 
        /// pak se registrace provede takto:
        /// a) podíl [0] = 10: operace 30 (poslední), množství 10, ToFuture od času 14 (původní čas počátku) = čas { 14 ÷ 17 }
        /// b) podíl [0] = 10: operace 20, množství 10, ToHistory od času 14 (reálný čas počátku tohoto podílu) = čas { 11 ÷ 14 }
        /// c) podíl [0] = 10: operace 10, množství 10, ToHistory od času 11 (reálný čas počátku operace 20 tohoto podílu) = čas { 9 ÷ 11 }
        /// d) podíl [1] =  8: operace 30 (poslední), množství 8, ToFuture od času 14 (původní čas počátku) = čas { 17 ÷ 19 } (volný čas počínaje časem 14)
        /// e) podíl [1] =  8: operace 20, množství 8, ToHistory od času 17 (reálný čas počátku tohoto podílu) = čas { 15 ÷ 17 }
        /// f) podíl [1] =  8: operace 10, množství 8, ToHistory od času 15 (reálný čas počátku operace 20 tohoto podílu) = čas { 13 ÷ 15 }
        /// g) podíl [2] =  2: operace 30 (poslední), množství 2, ToFuture od času 14 (původní čas počátku) = čas { 19 ÷ 20 } (volný čas počínaje časem 14)
        /// h) podíl [2] =  2: operace 20, množství 2, ToHistory od času 19 (reálný čas počátku tohoto podílu) = čas { 18 ÷ 19 }
        /// i) podíl [2] =  2: operace 10, množství 2, ToHistory od času 18 (reálný čas počátku operace 20 tohoto podílu) = čas { 17 ÷ 18 }
        /// </remarks>
        public TimeRange.TimeDirection RegisterTimeDir { get; protected set; }
        /// <summary>
        /// Aktuální dodavatel tohoto množství. Typicky zůstane Empty = zajistit tak, jako dosud (tj. výrobou).
        /// Lze ale vepsat GID dodavatele (číslo třídy + číslo subjektu dodavatele), pak se použije pro toto množství tento dodavatel, 
        /// a nebude se zajišťovat výroba, ale objednání (z uvedeného skladu / od dodavatele).
        /// </summary>
        public GID CurrentSupplier { get; set; }
        /// <summary>
        /// Aktuální T modifikace STPV, její klíč. Typicky zůstane 0 = určit nejvhodnější.
        /// Lze ale vepsat kladné číslo subjektu T modifikace STPV, která bude použita pro výrobu tohoto podílu výroby.
        /// Bude provedena kontrola, zda daná T modifikace STPV náleží dílci, který je na ose S evidován.
        /// </summary>
        public int CurrentAOMod { get; set; }
        /// <summary>
        /// Výsledné množství v návrhu na příjem. Od požadovaného množství se může lišit v případě, že byla aplikována pravidla skladové karty
        /// (maximální dávka, minimum od dodavatele, dělitel při nákupu).
        /// Pokud by pravidla skladové karty vedla k rozdělení na více maximálních dávek, bude zde jejich součet.
        /// </summary>
        public decimal ResultQty { get; internal set; }
        /// <summary>
        /// Soupis klíčů záznamů osy S, které byly založeny pro příjem zde požadovaného podílu v průběhu rozdělení výroby.
        /// Pokud by pravidla skladové karty vedla k rozdělení na více maximálních dávek, budou zde klíče všech záznamů osy S.
        /// Pokud se neaplikuje dělení na maximální dávky, bude zde jeden záznam.
        /// </summary>
        public List<GID> ResultAxisGIdList { get; internal set; }
        /// <summary>
        /// Seznam pointerů na elementy, které vznikly v průběhu rozdělení výroby, a který představuje výrobu zde požadovaného množství.
        /// Pokud by pravidla skladové karty vedla k rozdělení na více maximálních dávek, budou zde pointery na odpovídající element vždy za každý záznam osy S.
        /// Pokud se neaplikuje dělení na maximální dávky, bude zde jeden pointer.
        /// </summary>
        public List<DataPointerStr> ResultElementPointerList { get; internal set; }
        /// <summary>
        /// Libovolná informace, která doprovází toto požadované množství množství. 
        /// Je určeno pro volající aplikaci jako prostor pro libovolný identifikátor.
        /// </summary>
        public object Tag { get; set; }
    }
    /// <summary>
    /// Režim úpravy množství zadaného do položek (SplitItemList) do argumentu funkce pro rozdělení příjmu na osu S
    /// </summary>
    [Flags]
    public enum SplitAxisSQtyAdjustmentMode
    {
        /// <summary>
        /// Žádná úprava: množství zadané v parametrech funkce se objeví jako návrh příjmu na záznamu osy S
        /// </summary>
        None = 0,
        /// <summary>
        /// Úprava dle stavu skladu (minimum od dodavatele, maximální dávka)
        /// </summary>
        AdjustByStockCard = 1,
        /// <summary>
        /// Úprava o ztráty na dílci (pevné a procentuální ztráty dle K modifikace)
        /// </summary>
        AdjustByElementLoss = 2,
        /// <summary>
        /// Standardní úprava (dle stavu skladu i dle ztrát na dílci)
        /// </summary>
        AdjustStandard = AdjustByStockCard | AdjustByElementLoss
    }
    #endregion
    #endregion
    #region CLASS PlanningInteractiveSplitTaskCArgs : Data pro řízení interaktivního rozdělení průchodu operací
    /// <summary>
    /// PlanningInteractiveSplitTaskCArgs : Data pro řízení interaktivního rozdělení průchodu operací
    /// </summary>
    public class PlanningInteractiveSplitTaskCArgs : PlanningInteractiveRegisterArgs
    {
        #region KONSTRUKCE A PROMĚNNÉ
        /// <summary>
        /// Konstruktor argumentu
        /// </summary>
        public PlanningInteractiveSplitTaskCArgs()
        {
            this.SplitItemList = new List<PlanningInteractiveSplitTaskCItemArgs>();
        }
        #endregion
        #region PUBLIC PROPERTY (dostupné pro uživatele služby)
        /// <summary>
        /// Položka, kterou je třeba rozdělit na více dílčích příjmů.
        /// Typicky by mělo jít o pointer na WorkUnit (element v grafu TaskLink), což je nejmenší jednotka práce.
        /// Alternativně je možno zadat pointer na celý task (element v grafu Gantt), tedy jde o operaci.
        /// Musí jít o operaci z NÁVRHU NA PŘÍJEM (kategorie Plán), nelze rozdělit VÝROBNÍ PŘÍKAZ (kategorie Realita)!
        /// </summary>
        public DataPointerStr SplitItemSource { get; set; }
        /// <summary>
        /// <para>
        /// Vstupní a výstupní pole, kde je zadáno požadované množství jednotlivých paralelních průchodů, 
        /// které mají vzniknout při rozdělení stávajícího množství zadaného průchodu.
        /// </para>
        /// <para>
        /// MNOŽSTVÍ: součet množství z jednotlivých položek SplitItemList[xx].QtyRequired by měl být shodný s původním množstvím 
        /// na původním průchodu. Jedna položka může obsahovat tzv. divokou kartu, položku do které se vloží zbývající množství.
        /// Pokud se bude množství lišit, pak dojde k chybě (nelze měnit množství na jedné z operací).
        /// </para>
        /// </summary>
        public List<PlanningInteractiveSplitTaskCItemArgs> SplitItemList { get; set; }
        /// <summary>
        /// Obsahuje (vždy vypočítá) součet množství QtyRequired ze všech jednotlivých položek seznamu SplitItemList.
        /// Obsahuje součet z pevně daných položek
        /// </summary>
        public decimal QtyRequiredSum { get { return this.SplitItemList.Sum(item => item.QtyRequired); } }
       
        /// <summary>
        /// Pokusí se zajistit, že položky SplitItemList budou v součtu dávat dané množství.
        /// Zjistí, jaké je požadované množství (QtyRequiredSum), a do první volatilní položky vepíše zbývající množství, pokud je kladné.
        /// Vrací číslo: 0M = OK, kladné = o kolik je zadáno více, než je požadované celkové množství, záporné = kolik se nepodařilo přidat do QtyRemaining.
        /// </summary>
        /// <param name="taskQty">Vyráběné množství v tasku</param>
        /// <returns>Rozdíl výsledného množství proti požadavku</returns>
        internal decimal SplitItemPrepareVolatileQty(decimal taskQty)
        {
            this.SplitItemList.ForEach(i => i.ClearIncreaseQty());

            decimal requiredSum = this.QtyRequiredSum;
            if (requiredSum >= taskQty) return (requiredSum - taskQty);       // Pokud je QtyRequiredSum == taskQty, vracím 0. Pokud je QtyRequiredSum > taskQty, vracím kladné číslo = nevypořadatelný rozdíl (množství nelze automatem snížit).

            decimal increasedQty = taskQty - requiredSum;                     // Množství, o kolik musíme navýšit první volatilní položku
            foreach (PlanningInteractiveSplitTaskCItemArgs item in this.SplitItemList)
            {
                if (increasedQty == 0m) break;
                if (item.IsVolatileQty)
                {
                    item.SetQtyIncreased(increasedQty);                       // Zadám volatilní množství, mělo by projít do item.QtyRemaining
                    increasedQty -= item.QtyIncreased;                        // Měla by vyjít hodnota 0.0M
                }
            }
            return -increasedQty;                                             // Pokud jsme nenašli žádnou volatilní položku, pak mi v increasedQty zbylo kladné množství, které jsme nikam nedali. Vrátíme jej jako chybu...
        }
        #endregion
        #region INTERNAL PROPERTY (potřebné pro interaktivní plánovací proces)
        /// <summary>
        /// Úložiště pro původní záznam aktuálního tasku, na který uživatel kliknul.
        /// V průběhu přeregistrace se v tomto tasku změní počet průchodů (WorkPassList).
        /// Task jako takový se nemění, ani jeho vztahy do okolí!
        /// </summary>
        internal CapacityPlanWorkItemCls CurrTaskData { get; set; }
        /// <summary>
        /// Úložiště pro záznam paralelního průchodu, který se bude měnit.
        /// Průchod zůstává stále platný, odeberou se (odregistrují) jeho kapacity, změní se jeho množství a zaregistruje se znovu.
        /// </summary>
        internal WorkPassCls CurrWorkPass { get; set; }
        /// <summary>
        /// Časový interval vybraného kapacitního úkolu - původní, před zahájením akce
        /// </summary>
        internal TimeRange OriginalTaskTimeRange { get; set; }
        /// <summary>
        /// Časový interval vybraného paralelního průchodu - původní, před zahájením akce
        /// </summary>
        internal TimeRange OriginalPassTimeRange { get; set; }
        /// <summary>
        /// Úložiště pro původní záznam o elementu, na který uživatel kliknul.
        /// V průběhu přeregistrace se tento element odebere z Axis, z jeho tasku (při odregistraci kapacit) i z kapacitního systému.
        /// Tady zbyde jen sirotek objekt, na konci funkce se argument vynuluje a tím se uvolní i tento sirotek.
        /// </summary>
        internal WorkUnitCls CurrWorkUnit { get; set; }
        /// <summary>
        /// Relativní pozice elementu, který byl předán jako aktivní, v rámci jeho WorkPass
        /// </summary>
        internal WorkUnitLocationCls CurrElementLocation { get; set; }
        /// <summary>
        /// Úložiště pro původní záznam posledního tasku, který je finální operací před příjmem na osu, kterou budu dělit.
        /// V průběhu přeregistrace se tento task odebere z Axis i z kapacitního systému, jeho vnitřní struktura se rozloží a vynuluje.
        /// Tady zbyde jen skořápka = hlavička, a na konci funkce se vynuluje a uvolní i zbytek záznamu.
        /// </summary>
        internal CapacityPlanWorkItemCls LastTaskData { get; set; }
        /// <summary>
        /// Časový interval posledního tasku.
        /// Při požadavku na registraci ve směru ToFuture se bude vycházet při registraci poslední operace z tohoto času (Begin).
        /// Veškeré podřízené operace budou zaplánovány ToHistory od času Begin z vyšší operace.
        /// </summary>
        internal TimeRange LastTaskTime { get; set; }
        /// <summary>
        /// Úložiště pro původní záznam osy S, který odebíráme (z něj budu dělat dílčí příjmy).
        /// V průběhu přeregistrace se odebere z osy AxisHeap, odstraní se návazné pohyby na skladové kartě StockCard, 
        /// odeberou se a zahodí záznamy task, které se na tento záznam odkazují (ve své property Parent).
        /// Tady zbyde jen sirotek objekt, na konci funkce se argument vynuluje a tím se uvolní i tento sirotek.
        /// </summary>
        internal MaterialPlanAxisItemCls FinalAxisSData { get; set; }
        /// <summary>
        /// Úložiště pro skladovou kartu odpovídající záznamu osy S OriginalAxis, tam bude probíhat přeplánování cílového záznamu osy S.
        /// Tato skladová karta se v průběhu přeregistrace mění, ale nezahazuje se - stále je to karta, na které se plánuje.
        /// </summary>
        internal StockCardCls FinalStockCard { get; set; }
        /// <summary>
        /// Index záznamu o pohybu na skladové kartě, kde se nacházel původní záznam osy S (OriginalAxis), který se odebral,
        /// a kam budeme vkládat nově vystavené návrhy na příjem vzniklé rozdělením
        /// </summary>
        internal int FinalStockChangeIndex { get; set; }
        #endregion
    }
    #region CLASS PlanningInteractiveSplitTaskCItemArgs : Jedna položka při zadání požadavku na dělení průchodu výrobou
    /// <summary>
    /// PlanningInteractiveSplitTaskCItemArgs : Jedna položka při zadání požadavku na dělení průchodu výrobou
    /// </summary>
    public class PlanningInteractiveSplitTaskCItemArgs
    {
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby.</param>
        /// <param name="registerVector">Vektor registrace kapacit (Od jakého data, kterým směrem). Směr musí být zadán, datum nemusí. Viz property RegisterTimeVector.</param>
        public PlanningInteractiveSplitTaskCItemArgs(decimal qtyRequired, TimeVector registerVector)
        {
            this._Init(qtyRequired, registerVector, false, null);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby.</param>
        /// <param name="registerVector">Vektor registrace kapacit (Od jakého data, kterým směrem)</param>
        /// <param name="tag">Libovolný objekt s daty, který je v této položce uložen pro identifikaci na straně volající aplikace.</param>
        public PlanningInteractiveSplitTaskCItemArgs(decimal qtyRequired, TimeVector registerVector, object tag)
        {
            this._Init(qtyRequired, registerVector, false, tag);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby.</param>
        /// <param name="registerVector">Vektor registrace kapacit (Od jakého data, kterým směrem). Směr musí být zadán, datum nemusí. Viz property RegisterTimeVector.</param>
        public PlanningInteractiveSplitTaskCItemArgs(decimal qtyRequired, bool isVolatileQty, TimeVector registerVector)
        {
            this._Init(qtyRequired, registerVector, isVolatileQty, null);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby.</param>
        /// <param name="registerVector">Vektor registrace kapacit (Od jakého data, kterým směrem)</param>
        /// <param name="tag">Libovolný objekt s daty, který je v této položce uložen pro identifikaci na straně volající aplikace.</param>
        public PlanningInteractiveSplitTaskCItemArgs(decimal qtyRequired, bool isVolatileQty, TimeVector registerVector, object tag)
        {
            this._Init(qtyRequired, registerVector, isVolatileQty, tag);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="registerVector">Vektor registrace kapacit (Od jakého data, kterým směrem)</param>
        public PlanningInteractiveSplitTaskCItemArgs(TimeVector registerVector)
        {
            this._Init(0M, registerVector, true, null);
        }
        /// <summary>
        /// Konstruktor pro jednu položku podílu, na který se má dělit příjem na osu S.
        /// </summary>
        /// <param name="qtyRequired">Množství požadované v tomto podílu rozdělené výroby.</param>
        /// <param name="registerVector">Vektor registrace kapacit (Od jakého data, kterým směrem)</param>
        /// <param name="tag">Libovolný objekt s daty, který je v této položce uložen pro identifikaci na straně volající aplikace.</param>
        public PlanningInteractiveSplitTaskCItemArgs(TimeVector registerVector, object tag)
        {
            this._Init(0M, registerVector, true, tag);
        }
        /// <summary>
        /// Inicializace hodnot
        /// </summary>
        /// <param name="qtyRequired"></param>
        /// <param name="registerVector"></param>
        /// <param name="isVolatileQty"></param>
        /// <param name="tag"></param>
        private void _Init(decimal qtyRequired, TimeVector registerVector, bool isVolatileQty, object tag)
        {
            this.QtyRequired = qtyRequired;
            this.IsVolatileQty = isVolatileQty;
            this.QtyIncreased = 0m;
            this.RegisterTimeVector = registerVector;
            this.ResultElementPointerList = new List<DataPointerStr>();
            this.Tag = tag;
        }
        /// <summary>
        /// Vloží hodnotu do QtyRemaining (pokud je položka IsVolatileQty)
        /// </summary>
        /// <param name="increasedQty"></param>
        internal void SetQtyIncreased(decimal increasedQty)
        {
            if (this.IsVolatileQty)
                this.QtyIncreased = increasedQty;
        }
        /// <summary>
        /// Vynuluje množství v QtyIncreased
        /// </summary>
        internal void ClearIncreaseQty()
        {
            this.QtyIncreased = 0m;
        }
        /// <summary>
        /// Množství požadované v tomto podílu rozdělené výroby.
        /// Toto množství nebude dále upravováno.
        /// Součet všech položek množství má odpovídat množství na paralelním průchodu, který se dělí.
        /// Je možno použít jednu položku s nezadaným množstvím, s nastaveným příznakem IsVolatileQty = true.
        /// Do této položky pak systém vloží zbývající množství do množství na paralelním průchodu.
        /// </summary>
        public decimal QtyRequired { get; protected set; }
        /// <summary>
        /// Zbývající množství do množství paralelního průchodu. Je vyplněno systémem.
        /// Obsahuje QtyRequired + QtyIncreased.
        /// </summary>
        public decimal QtyVolatile { get { return this.QtyRequired + this.QtyIncreased; } }
        /// <summary>
        /// Navýšení množství do cílového množství na paralelním průchodu.
        /// Výchozí je 0. Množství se navyšuje v procesu přípravy na přeplánování, a to pouze pro položky, které mají IsVolatileQty == true.
        /// </summary>
        public decimal QtyIncreased { get; protected set; }
        /// <summary>
        /// Příznak, že tato položka má pojmout celé zbývající množství původního paralelního průchodu.
        /// </summary>
        public bool IsVolatileQty { get; protected set; }
        /// <summary>
        /// Množství, které je vloženo do paralelního průchodu. 
        /// Buď jde o QtyRequired, nebo o QtyVolatile (u položky s IsVolatileQty == true).
        /// </summary>
        public decimal QtyWorkPass { get { return (this.IsVolatileQty ? this.QtyVolatile : this.QtyRequired); } }
        /// <summary>
        /// Vektor alokace kapacit nově registrovaného průchodu.
        /// Datum a směr registrace kapacity.
        /// Pokud bude datum ve vektoru rovno DateTime.MinValue, vezme se datum původního průchodu v daném směru.
        /// Směr vektoru musí být pouze ToFuture nebo ToHistory, nesmí být Stay.
        /// </summary>
        public TimeVector RegisterTimeVector { get; protected set; }
        /// <summary>
        /// Seznam pointerů na elementy, které vznikly v průběhu rozdělení výroby, a který představuje výrobu zde požadovaného množství.
        /// Pokud by pravidla skladové karty vedla k rozdělení na více maximálních dávek, budou zde pointery na odpovídající element vždy za každý záznam osy S.
        /// Pokud se neaplikuje dělení na maximální dávky, bude zde jeden pointer.
        /// </summary>
        public List<DataPointerStr> ResultElementPointerList { get; internal set; }
        /// <summary>
        /// Libovolná informace, která doprovází toto požadované množství množství. 
        /// Je určeno pro volající aplikaci jako prostor pro libovolný identifikátor.
        /// </summary>
        public object Tag { get; set; }
    }
    #endregion
    #endregion
    #region CLASS PlanningInteractiveLinkArgs : Data pro řízení interaktivního linkování operací
    /// <summary>
    /// PlanningInteractiveLinkArgs : Data pro řízení interaktivního linkování operací
    /// </summary>
    public class PlanningInteractiveLinkArgs : PlanningInteractiveArgs
    {
        #region KONSTRUKCE A PROMĚNNÉ
        /// <summary>
        /// Konstruktor
        /// </summary>
        public PlanningInteractiveLinkArgs()
        {
            this.LinkSetting = InteractiveLinkSetting.NoChange;
        }
        #endregion
        #region PROPERTY
        /// <summary>
        /// Režim linkování. Default = NoChange
        /// </summary>
        public InteractiveLinkSetting LinkSetting { get; set; }
        /// <summary>
        /// <para>
        /// Objekt, který slouží jako vazba mezi operacemi.
        /// Na vstupu může být null.
        /// </para>
        /// <para>
        /// Pokud je volaná funkce pro UnLink, pak by měl být null a taky null zůstane.
        /// </para>
        /// <para>
        /// Pokud je volaná funkce pro nějaký Link, pak může obsahovat nový objekt, skrze který se budou operace linkovat.
        /// Ale nemusí jej obsahovat, protože funkce si jej umí vytvořit interně, viz property LinkFolderNumber.
        /// </para>
        /// <para>
        /// Pokud je volaná funkce pro LinkToCollective, a ve skupině vybraných operací již existuje nějaký LinkObject, 
        /// pak se zde zadaný objekt nevyužije, operace se spojí do existujícího LinkObjectu a ten bude uložen sem. 
        /// Volající aplikace pak může detekovat identitu zdejšího objektu a reagovat na to.
        /// </para>
        /// </summary>
        public IRecord LinkObject { get; set; }
        /// <summary>
        /// Číslo záznamu, který bude použit jako linkovací klíč. 
        /// Pokud bude nenulové, použije se a na závěr se uloží do databáze do lcs.plan_unit_c_task.link.
        /// Systém se nestará o to, kde se číslo vzalo a zda bude záznam s tímto číslem uložen.
        /// </summary>
        public SqlInt32 LinkRecordNumber { get; set; }
        /// <summary>
        /// Číslo skupiny vztahů Link.
        /// Pokud je navázaný Link objekt (this.LinkObject není null), pak se číslo záznamu čte z jeho RecordNumber.
        /// Pokud Link objektu není navázaný, pak se číslo záznamu čte z LinkRecordNumber.
        /// Pokud není nastaveno nikde, vrací se 0 (ne Null).
        /// </summary>
        public int LinkGroup
        {
            get
            {
                if (this.LinkObject != null) return this.LinkObject.RecordNumber;
                if (!this.LinkRecordNumber.IsNull) return this.LinkRecordNumber.Value;
                return 0;
            }
        }
        /// <summary>
        /// Číslo Noris pořadače pro vytvoření nového Link objektu.
        /// Pořadač musí být třídy Obecný subjekt (13).
        /// Toto číslo se využije, když se bude vytvářet nový Link objekt, a v property this.LinkObject nebude žádný připraven.
        /// Pokud nebude uvedeno číslo pořadače, systém si najde první pořadač podle definice Noris vztahu : 
        /// 103313 - Vazby společných oper. (statický, ze třídy Kapacitní úkol, dbname lcs.plan_unit_c_task.link).
        /// </summary>
        public int LinkFolderNumber { get; set; }
        #endregion
    }
    #endregion
}
